﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;

namespace SimpleCLML.LogisticRegression
{
    /// <summary>
    /// Multiclass logistic regression model
    /// </summary>
    [Serializable]
    public class MulticlassLogisticRegression: ISerializable
    {
        /// <summary>
        /// All-vs-one logistic regressions for each class
        /// </summary>
        LogisticRegression[] models;
        
        // For deserialization        
        private MulticlassLogisticRegression(){}        

        
        public MulticlassLogisticRegression(int classCount, float[][] thetas)
        {
            models = new LogisticRegression[classCount];
            for (int i = 0; i < classCount; i++)
                models[i] = new LogisticRegression(thetas[i]);
        }

        /// <summary>
        /// Predict class
        /// </summary>
        /// <param name="x">Feature vector (MUST be one element shorter than θ)</param>
        /// <returns></returns>
        public int Predict(float[] x)
        {
            var t = models.Select((r, i) => new Tuple<int, float>(i, r.Predict(x))).OrderByDescending(i => i.Item2).First();
            return t.Item1;
        }

        public void Save(string filename)
        {
            using (var stream = File.Create(filename))
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(stream, this);
            }
        }

        public static MulticlassLogisticRegression Load(string filename)
        {
            using (var stream = File.OpenRead(filename))
            {
                BinaryFormatter bf = new BinaryFormatter();
                return (MulticlassLogisticRegression)bf.Deserialize(stream);
            }
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                throw new System.ArgumentNullException("info");

            info.AddValue("OneVsAllModels", models);
        }
    }
}
